package com.mybatis.sqlsession;

import com.mybatis.config.MyConfiguration;
import com.util.log.Logger;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.*;

/**
 * sql语句执行器
 */
public class MySqlExecutor implements SqlExecutor {
    private final static Logger log = Logger.getLogger(MySqlExecutor.class);

    /**
     * 获取sql连接
     */
    private final MyConfiguration configuration = new MyConfiguration();

    /**
     * @param sql        sql语句 eg: select * from user where id = ?;
     * @param parameters 查询参数
     * @param returnType 接口里的返回对象的Class eg:List<User>
     * @param resultType 接收sql执行结果的pojo对象的类型
     * @param <T>
     * @return
     */
    @Override
    public <T> T select(String sql, Object[] parameters, Class<?> returnType, Class<?> resultType) {
        ResultSet resultSet = null;
        try (Connection connection = configuration.getConnection();
             PreparedStatement preparedStatement = connection.prepareStatement(sql);) {
            // 设置参数
            if (parameters != null)
                for (int i = 0; i < parameters.length; i++)
                    preparedStatement.setObject(i + 1, parameters[i]);

            resultSet = preparedStatement.executeQuery();
            // 返回的列名
            Set<String> columnNames = new HashSet<>();
            ResultSetMetaData metaData = resultSet.getMetaData();
            for (int i = 0; i < metaData.getColumnCount(); i++)
                columnNames.add(metaData.getColumnName(i + 1));
            // 日志打印
            log.trace("[SELECT] 执行sql：" + sql);
            log.trace("参数：" + Arrays.toString(parameters));
            log.trace("返回的列名 " + columnNames);
            log.trace("返回结果的类型 " + returnType);
            log.trace("执行结果的pojo对象的类型" + resultType);

            // 通过反射方式注入并生成返回结果
            if (returnType.getName().equals("java.util.List")) { // 查询多个
                List list = new ArrayList();
                // 遍历结果集
                while (resultSet.next()) {
                    Object returnObject = resultType.newInstance();
                    for (String columnName : columnNames) {
                        Field field = resultType.getDeclaredField(columnName); // 注入字段属性
                        field.setAccessible(true);
                        field.set(returnObject, resultSet.getObject(columnName));
                    }
                    list.add(returnObject);
                }
                return (T) list;
            } else { // 查询一个
                if (resultSet.next()) {
                    Object returnObject = resultType.newInstance();
                    for (String columnName : columnNames) {
                        Field field = resultType.getDeclaredField(columnName); // 注入字段属性
                        field.setAccessible(true);
                        field.set(returnObject, resultSet.getObject(columnName));
                    }
                    return (T) returnObject;
                }
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * sql语句 eg: insert into user (username, password) values ('', '');
     *
     * @param pojo java对象
     * @param <T>
     * @return
     */
    @Override
    public <T> int insert(T pojo) {
        // 简单地生成insert sql语句并注入要插入数据库的对象
        StringBuilder sql = new StringBuilder("insert into " + pojo.getClass().getSimpleName() + " (");
        StringBuilder values = new StringBuilder(" values (");
        Field[] fields = pojo.getClass().getDeclaredFields();
        for (int i = 0; i < fields.length; i++) {
            fields[i].setAccessible(true);
            try {
                if (fields[i].get(pojo) != null) {
                    sql.append(fields[i].getName());
                    values.append("'").append(fields[i].get(pojo)).append("'");
                    if (i < fields.length - 1) {
                        sql.append(",");
                        values.append(",");
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        sql.append(")");
        values.append(")");
        sql.append(values);
        try (Connection connection = configuration.getConnection();
             PreparedStatement preparedStatement = connection.prepareStatement(sql.toString())) {
            int count = preparedStatement.executeUpdate();
            // 日志打印
            String logPrefix = "[log] [" + this.getClass().getTypeName() + "] ";
            log.trace("[INSERT] 执行sql：" + sql);
            log.trace("插入数据库pojo对象：" + pojo);
            log.trace("影响行数 " + count);

            return count;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }
}
